


#ifndef FORMAT_HPP
#define FORMAT_HPP

#include "message.hpp"
#include <memory>
#include <vector>
#include <sstream>
#include <cassert>

namespace xzt
{
    namespace log
    {
        // 格式化项基类
        class FormatItem
        {
        public:
            using ptr = std::shared_ptr<FormatItem>;
            virtual void format(std::ostream& os, const LogMsg& message) const = 0;
        };

        // 格式化项：时间戳
        class TimestampFormatItem : public FormatItem
        {
        public:
            #define DEFAULT_TIME_FMT "%Y-%m-%d %H:%M:%S"
            #define DEFAULT_TIME_SUB_FMT "%H:%M:%S"
            // 时间格式可以自由指定，决定是否包含年月日
            TimestampFormatItem(std::string time_fmt = DEFAULT_TIME_FMT): _time_fmt(time_fmt) {}
            void format(std::ostream& os, const LogMsg& message) const override
            {
                struct tm tm_time;
                time_t timestamp = message.getTimeStamp();
                // localtime_r() 函数是线程安全的，所以这里不选用 localtime() 函数
                localtime_r(&timestamp, &tm_time);
                char time_str[64];
                strftime(time_str, sizeof(time_str) - 1, _time_fmt.c_str(), &tm_time);
                os << time_str;
            }
        private:
            std::string _time_fmt;  // 用于指定时间格式
        };

        // 格式化项：线程ID
        class ThreadIdFormatItem : public FormatItem
        {
        public:
            void format(std::ostream& os, const LogMsg& message) const override
            {
                os << message.getThreadId();
            }
        };

        // 格式化项：日志级别
        class LevelFormatItem : public FormatItem
        {
        public:
            void format(std::ostream& os, const LogMsg& message) const override
            {
                os << Level::toString(message.getLevel());
            }
        };

        // 格式化项：文件名
        class FilenameFormatItem : public FormatItem
        {
        public:
            void format(std::ostream& os, const LogMsg& message) const override
            {
                os << message.getFilename();
            }
        };

        // 格式化项：行号
        class LineFormatItem : public FormatItem
        {
        public:
            void format(std::ostream& os, const LogMsg& message) const override
            {
                os << message.getLine();
            }
        };

        // 格式化项：日志名
        class LoggerNameFormatItem : public FormatItem
        {
        public:
            void format(std::ostream& os, const LogMsg& message) const override
            {
                os << message.getLoggerName();
            }
        };

        // 格式化项：日志内容
        class PayloadFormatItem : public FormatItem
        {
        public:
            void format(std::ostream& os, const LogMsg& message) const override
            {
                os << message.getPayload();
            }
        };

        // 格式化项：制表符
        class TabFormatItem : public FormatItem
        {
        public:
            void format(std::ostream& os, const LogMsg& message) const override
            {
                os << "\t";
            }
        };

        // 格式化项：换行符
        class NewlineFormatItem : public FormatItem
        {
        public:
            void format(std::ostream& os, const LogMsg& message) const override
            {
                os << "\n";
            }
        };

        // 格式化项：其他字符（串）
        class OtherFormatItem : public FormatItem
        {
        public:
            OtherFormatItem(const std::string& str) : _str(str) {}
            void format(std::ostream& os, const LogMsg& message) const override
            {
                os << _str;
            }
        private:
            std::string _str;  // 其他字符（串）
        };

        // 格式化器
        class Formatter
        {
        public:
            using ptr = std::shared_ptr<Formatter>;
            /*
                pattern: 格式化规则字符串，格式如下：
                    %d: 表示时间（包括子格式{%H:%M:%S}）
                    %t: 表示线程ID
                    %p: 表示日志级别
                    %f: 表示文件名
                    %l: 表示行号
                    %c: 表示日志器名
                    %m: 表示日志主体内容
                    %n: 表示换行符
                    %T: 表示制表符
                默认格式：[%d{%H:%M:%S}][%t][%p][%f:%l][%c]%T%m%n
            */
            Formatter(const std::string& pattern = "[%d{%H:%M:%S}][%t][%p][%f:%l][%c]%T%m%n") 
                : _pattern(pattern)
                {
                    assert(parsePattern());
                }

            // 对整体Message进行格式化
            void format(std::ostream& os, const LogMsg& message) const
            {
                for(auto item : _items)
                {
                    item->format(os, message);
                }
            }
            std::string format(const LogMsg& message) const
            {
                std::stringstream ss;
                format(ss, message);
                return ss.str();
            }

        private:
            // 对格式化规则字符串进行解析
            bool parsePattern()
            {
                // abc[%d{%H:%M:%S}][%t][%p][%f:%l][%c]%T%m%n
                // 1. 对格式化字符串进行解析
                std::vector<std::pair<std::string, std::string>> fmt_order;  // 格式化项顺序
                size_t pos = 0;
                std::string key, val;
                while(pos < _pattern.size())
                {
                    // 判断当前字符是否为%
                    if(_pattern[pos] != '%')
                    {
                        val += _pattern[pos++];
                        continue;
                    }

                    // 处理当前位置为%的情况
                    if(pos + 1 < _pattern.size() && _pattern[pos + 1] == '%')
                    {
                        // %%表示%
                        val += _pattern[pos];
                        pos += 2;
                        continue;
                    }
                    // 到这里说明当前位置为%，且下一位不是%%，原始字符串处理结束
                    if(!val.empty())  // 代表上面的if语句pos + 1 < _pattern.size()满足
                    {
                        fmt_order.emplace_back(std::make_pair("", val));
                        val.clear();
                    }

                    // 此时pos指向%
                    if(pos + 1 >= _pattern.size())
                    {
                        // 格式化字符串格式错误
                        std::cerr << "%后面缺少格式化字符" << std::endl;
                        return false;
                    }
                    // 处理%后面的格式化字符
                    key = _pattern[++pos];

                    // 处理%后面带有子格式的情况，目前业务中仅有%d后会有子格式
                    if(pos + 1 < _pattern.size() && _pattern[++pos] == '{')
                    {
                        pos++;  // 跳过{
                        while(pos < _pattern.size() && _pattern[pos] != '}')
                        {
                            val += _pattern[pos++];
                        }

                        if(pos >= _pattern.size())
                        {
                            // 未找到子格式结尾"}"
                            std::cerr << "子格式未找到结尾\"}\"" << std::endl;
                            return false;
                        }

                        pos++;  // 跳过}
                    }
                    fmt_order.emplace_back(std::make_pair(key, val));
                    key.clear();
                    val.clear();
                }
                
                // 2. 根据解析结果，初始化格式化项列表
                for(auto& item : fmt_order)
                {
                    _items.emplace_back(createItem(item.first, item.second));
                }
                return true;
            }

            // 根据不同的格式化字符，创建对应的格式化项对象
            // 若key为特殊字符，val值为子格式或为空；若key为空，val值为其他字符（串）
            FormatItem::ptr createItem(const std::string& key, const std::string& val) const
            {
                if(key.size() == 1)
                {
                    return createItem_c(key[0], val);
                }
                else
                {
                    // 用于处理连续的其他字符
                    return std::make_shared<OtherFormatItem>(key + val);
                }
            }
            FormatItem::ptr createItem_c(char key, const std::string& val) const
            {
                /*
                    %d: 表示时间（包括子格式{%H:%M:%S}）
                    %t: 表示线程ID
                    %p: 表示日志级别
                    %f: 表示文件名
                    %l: 表示行号
                    %c: 表示日志器名
                    %m: 表示日志主体内容
                    %n: 表示换行符
                    %T: 表示制表符
                */
               switch(key)
               {
                   case 'd': return std::make_shared<TimestampFormatItem>(val);
                   case 't': return std::make_shared<ThreadIdFormatItem>();
                   case 'p': return std::make_shared<LevelFormatItem>();
                   case 'f': return std::make_shared<FilenameFormatItem>();
                   case 'l': return std::make_shared<LineFormatItem>();
                   case 'c': return std::make_shared<LoggerNameFormatItem>();
                   case 'm': return std::make_shared<PayloadFormatItem>();
                   case 'n': return std::make_shared<NewlineFormatItem>();
                   case 'T': return std::make_shared<TabFormatItem>();
                   default: return std::make_shared<OtherFormatItem>(val);
               }
            }
        private:
            std::string _pattern;  // 格式化规则字符串
            std::vector<FormatItem::ptr> _items;  // 格式化项列表
        };
    }
}



#endif // FORMAT_HPP